package cn.changeforyou.cmd.generator;

import cn.changeforyou.cache.ehcache.EhCacheUtils;
import cn.changeforyou.utils.string.StringUtils;
import cn.changeforyou.validate.BeanValidator;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zhyu
 * @date 2021/2/4 12:07
 */
public interface CmdGenerator {

    Logger log = LoggerFactory.getLogger(CmdGenerator.class);

    ThreadLocal<GeneratorContext> contextLocal = new ThreadLocal<>();

    /**
     * 生成器的标识(字母)
     *
     * @return
     */
    String getSign();

    /**
     * 生成细节
     *
     * @param context
     * @param params
     * @return
     */
    boolean generate_do(GeneratorContext context, CmdGeneratorParameter params);

    /**
     * 生成器执行方法
     * @param context 
     * @param params
     * @return
     */
    default boolean generate(GeneratorContext context, CmdGeneratorParameter params){
        getContext().putCmdParameters(this, params);
        return generate_do(context, params);
    }
    /**
     * 获取中文名称
     *
     * @return
     */
    String getName();

    /**
     * 获取参数类型
     *
     * @return
     */
    Class getParameterClass();

    /**
     * @param parameter 
     * @return
     */
    default String getKey(CmdGeneratorParameter parameter) {
        return getSign() + "_" + parameter.getSign();
    }

    /**
     * 启动方法
     * @return
     */
    default boolean start() {
        GeneratorContext context = getContext();
        Scanner sc = context.getScanner();
        init(context);
        printNameInfo();
        Class parameterClass = getParameterClass();
        boolean result = false;
        if (null != parameterClass) {
            boolean find = false;
            Class[] interfaces = parameterClass.getInterfaces();
            if (null != interfaces || interfaces.length > 0) {
                for (Class aClass : interfaces) {
                    if (aClass == CmdGeneratorParameter.class) {
                        find = true;
                        break;
                    }
                }

            }
            if (!find) {
                throw new RuntimeException("参数类型没有按照规范继承 CmdGeneratorParameter");
            }
            try {
                CmdGeneratorParameter parameter = (CmdGeneratorParameter) parameterClass.newInstance();
                String cacheStr = EhCacheUtils.get(getKey(parameter));
                EhCacheUtils.close();
                if (null != cacheStr) {
                    log.info("发现缓存的数据[: " + cacheStr + "   ] 请问是否使用, 使用Y, 部分使用自己粘贴复制, 按别的取消");
                    String answer = sc.nextLine();
                    if (answer.equalsIgnoreCase("Y")) {
                        result = this.parseParamsAndDo(cacheStr, context, parameter);
                    } else {
                        log.info("参数:");
                    }
                }
                if (!result) {
                    String nextLine = null;
                    while (null != (nextLine = sc.nextLine())) {
                        if (StringUtils.isEmpty(nextLine)) {
                            continue;
                        }
                        if (this.parseParamsAndDo(nextLine, context, parameter)) {
                            result = true;
                            break;
                        }
                    }
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        } else {
            result = this.generate(context, null);
        }
        context.closeScanner();
        return result;
    }

    default void printNameInfo() {
        log.info("-------------------         ----------------------");
        log.info("进入《" + getName() + "》生成器, 作者: zhyu 查看帮助 -h");
    }

    /**
     * 解析参数并执行
     *
     * @param nextLine
     * @param context
     * @param parameter
     * @return
     */
    default boolean parseParamsAndDo(String nextLine, GeneratorContext context, CmdGeneratorParameter parameter) {
        JCommander jct = JCommander.newBuilder()
            .addObject(parameter)
            .build();
        try {
            jct.parse(nextLine.split(" "));
        } catch (ParameterException e) {
            log.info("参数错误, 请重新输入, 可以输入-h 查看帮助文档");
            if (log.isDebugEnabled()) {
                log.error("parse error", e);
            }
            return false;
        }
        if (parameter.isHelp()) {
            jct.usage();
            parameter.isHelp(false);
        } else {
            if (!validateParamsIsOk(parameter)) {
                return false;
            } else {
                boolean result = this.generate(context, parameter);
                if (result) {
                    EhCacheUtils.put(getKey(parameter), nextLine);
                    EhCacheUtils.close();
                }
                return true;
            }
        }
        return false;
    }

    /**
     * 校验参数
     *
     * @param parameter
     * @return
     */
    default boolean validateParamsIsOk(CmdGeneratorParameter parameter) {
        Map<String, String> map = BeanValidator.validateObject(parameter);

        if (map.isEmpty()) {
            if (!parameter.check()) {
                log.info("参数自定义检查失败");
                return false;
            }
            return true;
        }
        for (Entry<String, String> entry : map.entrySet()) {
            log.info("参数" + entry.getKey() + " " + entry.getValue());
        }
        return false;
    }

    /**
     * 获取默认的注释, 方便其他类获取
     * @return 
     */
    static GeneratorContext getDefaultContext(){
        return contextLocal.get();
    }
    
    /**
     * 获取上下文
     *
     * @return
     */
    default GeneratorContext getContext() {
        GeneratorContext context = contextLocal.get();
        if (null == context) {
            log.info("欢迎使用生成器: 《" + getName() + "》");
            context = new GeneratorContext();
        }
        contextLocal.set(context);
        return context;
    }

    /**
     * 初始化方法
     *
     * @param context
     */
    void init(GeneratorContext context);

}
